function s = logfun(varargin)

% How to use:
%
% To log all functions currently in memory (under some base path):
%  log = logfun(findfun(basepath))
% 
% To log a specific function or functions:
%  log = logfun(funcname)
%  log = logfun({funcname1, funcname2, ...})
% 
% To log files in a directory:
%  log = logfun(dirname, filepattern)
% 
% To add to an existing log:
%  log = logfun(log, ...)
% 
% Program written by Jim Mutch






args = varargin;

if (numel(args) >= 1) && isstruct(args{1})
    s = args{1};
    if isempty(s) || isempty(fieldnames(s))
        s = EmptyStruct;
    elseif isempty(setxor(fieldnames(s), fieldnames(EmptyStruct)))
    else
        error('invalid arguments');
    end
    args = args(2 : end);
else
    s = EmptyStruct;
end

if (numel(args) == 1) && iscell(args{1})
    dirname   = '';
    funcnames = args{1};
elseif numel(args) == 1
    dirname   = '';
    funcnames = args(1);
elseif (numel(args) == 2) && iscell(args{2})
    dirname   = args{1};
    funcnames = args{2};
elseif numel(args) == 2
    dirname   = args{1};
    funcnames = args(2);
else
    error('invalid arguments');
end

for i = 1 : numel(funcnames)
    if ischar(funcnames{i})
        if isempty(dirname) && isempty(regexp(funcnames{i}, '\.m$', 'once'))
            funcnames{i} = [funcnames{i} '.m'];
        end
    elseif isa(funcnames{i}, 'function_handle')
        funcnames{i} = [func2str(funcnames{i}) '.m'];
    else
        error('invalid arguments');
    end
end

if isempty(dirname)

    for i = 1 : numel(funcnames)

        path = which(funcnames{i});
        if isempty(path), error('function "%s" not found', funcnames{i}); end

        s = Add(s, funcnames{i}, path);

    end

else

    base = what(dirname);
    if isempty(base), error('directory "%s" not found', dirname); end
    if numel(base) > 1, error('more than one "%s" directory found', dirname); end
    base = base.path;

    for i = 1 : numel(funcnames)

        [path, name, ext] = fileparts(funcnames{i});
        if isempty(path)
            abs = base;
            rel = dirname;
        else
            abs = fullfile(base   , path);
            rel = fullfile(dirname, path);
        end
        pattern = [name ext];

        list = dir(fullfile(abs, pattern));

        for j = 1 : numel(list)
            s = Add(s, fullfile(rel, list(j).name), fullfile(abs, list(j).name));
        end

    end

end

return;

%***********************************************************************************************************************

function s = EmptyStruct

s = struct('name', {}, 'body', {}, 'moddate', {}, 'logdate', {});

return;

%***********************************************************************************************************************

function s = Add(s, name, path)

info = dir(path);

body    = ReadFile(path);
moddate = datestr(info.datenum, 31);
logdate = datestr(now         , 31);

pos = numel(s) + 1;

for i = 1 : numel(s)
    [dummy, fname1, ext1] = fileparts(s(i).name);
    [dummy, fname2, ext2] = fileparts(name     );
    if strcmp([fname1 ext1], [fname2 ext2]) && strcmp(s(i).body, body)
        pos = i;
        break;
    end
end

s(pos).name    = name;
s(pos).body    = body;
s(pos).moddate = moddate;
s(pos).logdate = logdate;

return;

%***********************************************************************************************************************

function body = ReadFile(path)

f = fopen(path, 'r');
if f < 0, error('unable to open "%s"', path); end

body = fread(f, '*char')';

fclose(f);

body = strrep(body, sprintf('\r\n'), sprintf('\n'));

return;